<template>
  <div>
    <el-switch v-model="draggable" active-text="开启拖拽" inactive-text="关闭拖拽"></el-switch>
    <el-button type="success" v-if="draggable" @click="batchSave" size="mini">批量保存</el-button>
    <el-button type="danger" @click="batchDelete" size="mini">批量删除</el-button>
    <br />
    <br />
    <el-tree :data="menus" :props="defaultProps" :expand-on-click-node="false" show-checkbox node-key="catId" :default-expanded-keys="expandedKey" :draggable="draggable" :allow-drop="allowDrop" @node-drop="handleDrop" ref="menuTree">
      <span class="custom-tree-node" slot-scope="{ node, data }">
        <span>{{ node.label }}</span>
        <span>
          <el-button v-if="node.level <= 2 && !draggable" type="text" size="mini" @click="() => append(data)">Append</el-button>
          <el-button v-if="!draggable" type="text" size="mini" @click="() => edit(data)">Edit</el-button>
          <el-button v-if="node.childNodes.length == 0 && !draggable" type="text" size="mini" @click="() => remove(node, data)">Delete</el-button>
        </span>
      </span>
    </el-tree>

    <el-dialog :title="title" :visible.sync="dialogVisible" width="30%" :close-on-click-modal="false">
      <el-form :model="category">
        <el-form-item label="分类名称">
          <el-input v-model="category.name" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="图标">
          <el-input v-model="category.icon" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="计量单位">
          <el-input v-model="category.productUnit" autocomplete="off"></el-input>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="dialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="submitData">确 定</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
// 这里可以导入其他文件（比如：组件、工具js、第三方插件js、json文件、图片文件等）
// 格式：import 组件名称 from '组件路径'

export default {
  // import引入的组件需要注入到对象中才能使用
  name: "category",

  data() {
    return {
      pCids: [],
      draggable: false,

      updateNodes: [], //需要更新的节点集合
      maxLevel: 0, //正在拖拽节点的最大深度

      title: "",
      dialogType: "", //add, edit
      dialogVisible: false,

      category: {
        catId: null,
        name: "",
        parentCid: 0,
        catLevel: 0,
        showStatus: 1,
        sort: 0,
        productUnit: "",
        icon: "",
      },

      menus: [],

      expandedKey: [],

      defaultProps: {
        children: "children",
        label: "name",
      },
    };
  },
  methods: {
    //添加分类弹框
    append(data) {
      console.log("append：", data);

      this.title = "添加分类";
      this.dialogType = "add";
      this.dialogVisible = true;

      this.category.parentCid = data.catId;
      this.category.catLevel = data.catLevel * 1 + 1; //*1是以防catLevel是字符串，如是转换后+1

      this.category.name = "";
      this.category.icon = "";
      this.category.productUnit = "";
      this.category.catId = null;
    },

    //修改分类弹框
    edit(data) {
      console.log("edit: ", data);

      this.title = "修改分类";
      this.dialogType = "edit";
      this.dialogVisible = true;

      this.$http({
        url: this.$http.adornUrl(`/product/category/info/${data.catId}`),
        method: "get",
      }).then(({ data }) => {
        console.log("查询分类信息成功：", data);

        this.category.catId = data.data.catId;
        this.category.parentCid = data.data.parentCid;
        this.category.name = data.data.name;
        this.category.icon = data.data.icon;
        this.category.productUnit = data.data.productUnit;
      });
    },

    //提交数据
    submitData() {
      if (this.dialogType === "add") {
        this.addCategory();
      } else if (this.dialogType == "edit") {
        this.editCategory();
      }
    },

    // 添加分类(提交表单数据category)
    addCategory() {
      console.log("提交的三级分类数据", this.category);
      this.$http({
        url: this.$http.adornUrl("/product/category/save"),
        method: "post",
        data: this.$http.adornData(this.category, false),
      }).then(({ data }) => {
        this.$message({
          message: "菜单保存成功",
          type: "success",
        });
        this.dialogVisible = false; //关闭对话框
        this.getMenus(); //刷新菜单数据
        this.expandedKey = [this.category.parentCid]; //设置默认展开的节点
      });
    },

    // 修改分类
    editCategory() {
      var { catId, name, icon, productUnit } = this.category;
      // var queryData = {catId: catId,name: name,icon: icon,productUnit:productUnit};
      var queryData = { catId, name, icon, productUnit };
      console.log("要提交的修改数据", queryData);
      this.$http({
        url: this.$http.adornUrl("/product/category/update"),
        method: "post",
        data: this.$http.adornData(queryData, false),
      }).then(({ data }) => {
        this.$message({
          message: "菜单更新成功",
          type: "success",
        });
        this.dialogVisible = false; //关闭对话框
        this.getMenus(); //刷新菜单数据
        this.expandedKey = [this.category.parentCid]; //设置默认展开的节点
      });
    },

    //删除分类
    remove(node, data) {
      console.log("remove：", node, data);
      this.$confirm(`是否删除【${data.name}】菜单?`, "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      })
        .then(() => {
          var ids = [data.catId];
          this.$http({
            url: this.$http.adornUrl("/product/category/delete"),
            method: "post",
            data: this.$http.adornData(ids, false),
          }).then(({ data }) => {
            this.$message({
              message: "删除菜单成功",
              type: "success",
            });
            this.getMenus(); //刷新菜单数据
            this.expandedKey = [node.parent.data.catId]; //设置默认展开的节点
          });
        })
        .catch(() => { });
    },

    //获取菜单
    getMenus() {
      this.$http({
        url: this.$http.adornUrl("/product/category/list/tree"),
        method: "get",
      }).then(({ data }) => {
        //{ data } : 对data进行解构
        console.log("查询三级菜单数据成功：", data.data);
        this.menus = data.data;
      });
    },

    //判断节点是否被拖拽:
    //原则：拖动后的总层数不能超过3
    //方案：inner 被拖动节点的总层数 + 目标节点的层数 <= 3
    //     prev或next 被拖动节点的总层数 + 目标节点的父节点层数 <= 3
    allowDrop(draggingNode, dropNode, type) {
      console.log(
        "=========================allowDrop==============================",
        draggingNode,
        dropNode,
        type
      );
      console.log(
        "draggingNode",
        draggingNode.data.name,
        draggingNode.data.catLevel,
        draggingNode.parent.level
      );
      console.log(
        "dropNode",
        dropNode.data.name,
        dropNode.data.catLevel,
        dropNode.parent.level
      );
      console.log("type", type);

      //1) 计算被拖动节点的最大深度
      this.countNodeLevel(draggingNode); //如被拖节点最大层为：3
      console.log("当前拖动节点的最大深度：", this.maxLevel);

      //2) 当前拖动节点的深度：(即该节点有几层)
      let draggingDeep = Math.abs(this.maxLevel - draggingNode.level) + 1; //如被拖节点在第二层，3 - 2 + 1 = 2，即被拖节点共有2层
      console.log("当前拖动节点的深度：", draggingDeep);

      //3) 当前拖动节点的深度 + 目标节点层数 <= 3
      let tarLevel =
        type == "inner"
          ? draggingDeep + dropNode.level
          : draggingDeep + dropNode.parent.level;
      console.log("拖拽后的总层数", tarLevel);

      return tarLevel <= 3;
    },

    // 递归遍历所有子节点，求出最大深度
    countNodeLevel(node) {
      if (node.childNodes != null && node.childNodes.length > 0) { //有子节点
        for (var i = 0; i < node.childNodes.length; i++) {
          if (node.childNodes[i].level > this.maxLevel) {
            this.maxLevel = node.childNodes[i].level;
          }
          this.countNodeLevel(node.childNodes[i]);
        }
      } else {
        this.maxLevel = node.level;
      }
    },

    //完成拖拽事件，dropType: before、after、inner
    handleDrop(draggingNode, dropNode, dropType, ev) {
      console.log(
        "---------------handleDrop--------------: ",
        draggingNode,
        dropNode,
        dropType
      );

      //1、当前拖拽节点的最新父节点id
      let pCid = 0; //父节点id
      let siblings = null; //兄弟节点集合
      if (dropType == "before" || dropType == "after") {
        pCid =
          dropNode.parent.data.catId == undefined
            ? 0
            : dropNode.parent.data.catId;
        siblings = dropNode.parent.childNodes;
      } else {
        pCid = dropNode.data.catId;
        siblings = dropNode.childNodes;
      }
      this.pCids.push(pCid);

      //2、当前拖拽节点的最新顺序
      let updateNode = null;
      for (let i = 0; i < siblings.length; i++) {
        if (siblings[i].data.catId == draggingNode.data.catId) {
          //如果是当前正在拖拽的节点
          let draggingLevel = draggingNode.level;
          if (siblings[i].level != draggingLevel) {
            //当前节点的层级发生变化
            draggingLevel = siblings[i].level;
            this.updateChildNodeLevel(siblings[i]); //3、当前拖拽节点的最新层级
          }
          updateNode = {
            catId: siblings[i].data.catId,
            sort: i,
            parentCid: pCid,
            catLevel: draggingLevel,
          };
        } else {
          updateNode = { catId: siblings[i].data.catId, sort: i }; //其他节点，改顺序即可
        }
        this.updateNodes.push(updateNode);
      }

      console.log("updateNodes：", this.updateNodes);
    },

    // 更新节点的所有子节点的层级
    updateChildNodeLevel(node) {
      if (node.childNodes.length > 0) {
        for (let i = 0; i < node.childNodes.length; i++) {
          this.updateNodes.push({
            catId: node.childNodes[i].data.catId,
            catLevel: node.childNodes[i].level,
          });
          this.updateChildNodeLevel(node.childNodes[i]);
        }
      }
    },

    //批量保存拖拽后的节点
    batchSave() {
      if (this.updateNodes != null && this.updateNodes.length > 0) {
        this.$http({
          url: this.$http.adornUrl("/product/category/update/sort"),
          method: "post",
          data: this.$http.adornData(this.updateNodes, false),
        }).then(({ data }) => {
          this.$message({
            message: "菜单顺序等修改成功",
            type: "success",
          });
          this.getMenus(); //刷新菜单数据
          this.expandedKey = this.pCids; //设置默认展开的节点

          this.updateNodes = []; //完成拖拽后，重置变量
          this.maxLevel = 0;
          this.pCids = [];
        });
      }
    },

    // 批量删除选中的节点
    batchDelete() {
      let checkedNodes = this.$refs.menuTree.getCheckedNodes();
      console.log("checkedNodes: ", checkedNodes);
      let ids = [];
      let names = [];
      for (let i = 0; i < checkedNodes.length; i++) {
        ids.push(checkedNodes[i].catId);
        names.push(checkedNodes[i].name);
      }
      console.log("ids: names: ", ids, names);
      this.$confirm(`是否批量删除【${names}】菜单?`, "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      })
        .then(() => {
          this.$http({
            url: this.$http.adornUrl("/product/category/delete"),
            method: "post",
            data: this.$http.adornData(ids, false),
          }).then(({ data }) => {
            this.$message({
              message: "批量删除菜单成功",
              type: "success",
            });
            this.getMenus(); //刷新菜单数据
          });
        })
        .catch(() => { });
    },
  },

  created() {
    this.getMenus();
  },
};
</script>

<style>
</style>